//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <winhack.h>
#include <elasys_server.h>
#include <driver.h>
#include <stdio.h>

class CTimer : public CDeviceDriver
{
public:
    CARAPI Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf & buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf & inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    virtual void Dispose() {delete this;}

    CTimer();

public:
    UINT    m_timerChannel;
};

EXTERN_C UINT StartTimer(int uDelay);
EXTERN_C void StopTimer(UINT timerId);

EXTERN_C void __stdcall TimerCallback(UINT wTimerID, UINT msg,
    DWORD dwUser, DWORD dw1, DWORD dw2)
{
    int i = 0;
    EventNotify(EVENT_TIMER0, 0, &i);
}

CTimer::CTimer()
{
    m_timerChannel = 0;
}

ECode CTimer::Read(
    /* [in] */ Int64 u64Offset,
    /* [in] */ Int32 bytesToRead,
    /* [out] */ MemoryBuf * pBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    if (pBuffer == NULL || !pBuffer->GetCapacity()) {
        return E_INVALID_ARGUMENT;
    }
    return g_pEventQueues->Read(EVENT_TIMER,
        bytesToRead, pBuffer, ppCompletionEvent);
}

ECode CTimer::Write(
    /* [in] */ Int64 u64Offset,
    /* [in] */ const MemoryBuf & buffer,
    /* [out] */ Int32 * pBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

extern IDeviceDriver *g_pMultiTimers;
ECode CTimer::Control(
    /* [in] */ Handle32 nControlCode,
    /* [in] */ const MemoryBuf & inBuffer,
    /* [out] */ MemoryBuf * pOutBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    if (nControlCode > 10) {
        return g_pMultiTimers->Control(
                /* [in] */ nControlCode,
                /* [in] */ inBuffer,
                /* [out] */ pOutBuffer,
                /* [out] */ ppCompletionEvent);
    }

    int timerInterval = *(int *)inBuffer.GetPayload();
    if (m_timerChannel && 0 == timerInterval) {//0 means stop timer
        StopTimer(m_timerChannel);
        m_timerChannel = 0;
        return NOERROR;
    }

    switch (nControlCode) {
        case 1:
            if (m_timerChannel) return E_ACCESS_DENIED;
            m_timerChannel = StartTimer(timerInterval);
            if (!m_timerChannel) return E_ACCESS_DENIED;
            break;
        case 2:
            StopTimer(m_timerChannel);
            m_timerChannel = 0;
            break;
        default:
            break;
    }
    return NOERROR;
}

EXTERN IDeviceDriver * CDECL CreateTimer(uint_t uDeviceNo, void *pvParameter)
{
    CTimer * pTimer0 = new CTimer;
    //printf("Create Timer0 [%x]\n", pTimer0);

    return (IDeviceDriver *)pTimer0;
}
